package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import io.netty.util.internal.StringUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * ClassName: TsLoginAspect
 * Package: com.atguigu.tingshu.common.login
 * Description:
 *
 * @Author 樊子翔
 * @Create 2024/11/24 10:24
 * @Version 1.0
 */
@Component
@Aspect
public class TsLoginAspect {
    @Autowired
    private RedisTemplate redisTemplate;
    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(tsLogin)")
    public Object doTsLoginAspect(ProceedingJoinPoint point,TsLogin tsLogin){
        //  如何判断用户是否登录的?
        /*
        1.  需要通过token 来判断用户是否登录!
            如果请求头中有token，则说明登录！否则，没有登录！
         */
        //  获取到请求头中的 token
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
        //  获取的请求对象
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String token = request.getHeader("token");
        //  判断注解的属性：
        if(tsLogin.required()){
            //  判断token 是否为空
            if(StringUtils.isEmpty(token)){
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //  根据token 从缓存(redis)中获取用户信息数据; user_info==UserInfo;
            String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX+token;
            UserInfo userInfo = (UserInfo)redisTemplate.opsForValue().get(userLoginKey);
            if(userInfo == null){
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //存储 用户id 到本地线程
            try {
                AuthContextHolder.setUserId(userInfo.getId());
                Object proceed = point.proceed();
                return proceed;
            } catch (Throwable e) {
                throw new RuntimeException(e);
            } finally {
                //释放本地内存，防止TreadLocal内存泄露
                AuthContextHolder.removeUserId();
            }
        }
        try {
            return point.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

    }
}
